
/***************************************************************************
 *   Copyright (C) 1997 to 2004 by Jonathan Duddington                     *
 *   email: jonsd@users.sourceforge.net                                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write see:                           *
 *               <http://www.gnu.org/licenses/>.                           *
 ***************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "kernel.h"
#include "os.h"
#include "menu.h"
#include "wimp.h"
#include "werr.h"
#include "dbox.h"
#include "flex.h"
#include "win.h"
#include "msgs.h"

#include "narc.h"
#include "hdrs.h"

#ifdef MemCheck
#include "MemCheck:Flex.h"
#endif


extern char *path_choices;
extern OPTIONS options;
extern BOX box_table[N_BOXES];
extern FOLDREC list_fr[N_LISTS];

extern char *refs_start;
extern int refs_length;
extern dbox dbox_reply;
extern int reply_supersede;
extern OPTIONS_MAILBOX *current_user;
extern char fname_temp2[];
extern char *mime_style_names[];



static int check_user_number(int user)
/************************************/
/* Check whether this is a valid user number, return 0 if not */
{
	int  c;

	user &= 0x1f;
	if(user==0)
		return(0);

	/* allow * (indicates wildcard in user addr) */
	if(((c=options.mailbox[user-1].email_addr[0])=='*') || isalnum(c))
		return(user);

	return(0);
}   /* end of check_user_number */



static void set_sig_from_newsgroup(TEXTR *t, char *newsgroup)
/***********************************************************/
{
	char *p;
	NEWSG *ng;

	/* look for first recognised newsgroup */
	while((ng = newsg_lookup2(newsgroup)) == NULL)
	{
		if((p = strchr(newsgroup,',')) == NULL)
			break;
		newsgroup = p+1;
	}

	if(ng != NULL)
	{
		if(ng->default_user > 0)
			user_select(t,ng->default_user-1,1);

		if((ng->signature[0] != 0) && (memcmp(ng->signature,"(user's",7)!=0))
			strcpy(t->selected_sig,ng->signature);
	}
}   /* set_sig_from_newsgroup */




static void reply_copy_cc(TEXTR *t,TEXTR *t_in,int outgoing, char *to_out)
/************************************************************************/
{
	int  c;
	int  i;
	char *p;
	char *p_end;
	char *out;
	char *out_end;
	int  first;
	int  user;
	char *user_addr;
	int  len;
	ARTICLE_OUT *art_out;
	FILE *f_list;
	char *buf;
	int  buf_length;
	char *p_match;
	char fname[128];

	art_out = t->art_out;

	i = 0;

	buf_length = art_out->cc_length + art_out->to_length+100;
	buf = malloc(buf_length+4);
	if(buf==NULL)
		return;

	if(art_out->cc_start != -1)
	{
		/* find the email addresses in the cc: part of the header */
		p = &t_in->text_base[art_out->cc_start];
		p_end = p + art_out->cc_length;

		while((p < p_end) && (i < buf_length))
		{
			c = *p++;
			if((c == ' ') || (c == '\t'))
			{
				continue;
			}
			buf[i++] = c;
		}
		buf[i++] = ' ';
	}

	/* don't add the To: addresses if it's a maillist article
	   - really we should any the To: addresses *except* the maillist address */

	p = &t_in->text_base[art_out->to_start];
	p_end = p + art_out->to_length;

	if(outgoing == 0)
	{
		while((p < p_end) && (i < buf_length))
		{
			c = *p++;
			if((c == ' ') || (c == '\t')) continue;
			buf[i++] = c;
		}
	}

	buf[i]=' ';
	buf[i+1] = 0;

	f_list = NULL;
	if(i > 200)
	{
		/* make a copy of the CC list in a distribution list */
		sprintf(fname,"%s.Maillists.%s",path_choices,cc_list_name(t,"CC"));
		f_list = fopen_werr(fname,"w",NULL);
		if(f_list != NULL)
		{
			fprintf(f_list,"!Cc:\n");
		}
	}

	first=1;
	out = art_out->cc;
	out_end = out + sizeof(art_out->cc);
	out[0] = 0;

	user_addr = NULL;
	user = t_in->cptr->user & 0x1f;
	if(user > 0)
		user_addr = options.mailbox[user-1].email_addr;

	/* copy Cc and To addresses into Cc of outgoing message, unless
	   they match our own email address or are already in the To field of the reply */
	p = buf;
	for(;;)
	{
		p = reply_extract_email_addr(p,0);
		if(p == NULL)
			break;

		if((user_addr != NULL) && (user_addr[0]=='*'))
		{
			/* this message was matched to a wildcard email address */
			len = strlen(user_addr)-1;

			if(strcmp_lc(&user_addr[1],&p[strlen(p)-len])==0)
			{
				/* found an address that matches the wildcard - use this
				   as the From: address */
				strncpy0(art_out->user_addr,p,sizeof(art_out->user_addr));
				p += (strlen(p) + 1);
				continue;
			}
		}

		if((user_addr == NULL) || (strcmp_lc(p,user_addr)!=0))
		{
			if(((p_match = strstr(to_out,p)) == NULL) || ((p_match > to_out) && (isalnum(p_match[-1]))))
			{
				if((out+strlen(p)+1) < out_end)
				{
					if(first)
					{
						strcpy(out,p);
						out += strlen(p);
						first=0;
					}
					else
					{
						sprintf(out,",%s",p);
						out += strlen(p)+1;
					}
				}

				/* add to temporary distribution list in case we need it */
				if(f_list != NULL)
				{
					fprintf(f_list,"%s\n",p);
				}
			}
		}
		p += (strlen(p) + 1);
	}

	if(f_list != NULL)
		fclose(f_list);
	free(buf);
}   /* end of reply_copy_cc */







static int reply_find_newsgroups(TEXTR *t, ARTICLE_OUT *art_out)
/**************************************************************/
{
	int  i;
	int  c;
	int start=0;
	char *p;
	int  argument2;
	int  arg_end;
	int  newsgroups = -1;
	int  followup = -1;
	int  arg_length;
	int  quoting;

	art_out->in_reply_to[0] = 0;
	art_out->message_id[0] = 0;
	art_out->refs_length = 0;
	art_out->reply_to_in = -1;
	art_out->cc_start = -1;
	art_out->to_start = -1;

	if(t->internet_header)
	{
		/* keep looking until end of internet header, regardless of blank lines
		   This is needed in case of header re-arrangement with multipart-mime */
		while((c = interpret_article_key(&t->text_base,&start,t->internet_header,&argument2,&arg_end)) != -2)
		{
			arg_length = arg_end - argument2;

			switch(c)
			{
			case -1:   /* blank line */
				start = arg_end;
				while((start <= t->internet_header) && (t->text_base[start] == '\n'))
					start++;
				break;

			case 1:    /* From */
				art_out->from = argument2;
				art_out->from_length = arg_length;
				break;

			case 2:    /* Subject */
				art_out->subject_start = argument2;
				art_out->subject_length = arg_length;
				break;

			case 4:    /* Newsgroups */
				newsgroups = argument2;
				break;

			case 7:   /* To */
				art_out->to_start = argument2;
				art_out->to_length = arg_length;
				break;

			case 8:   /* References */
				i  = arg_length;
				if(i > refs_length)
				{
					if(refs_start != NULL)
						free(refs_start);

					refs_length = 0;
					refs_start = malloc(i);
					if(refs_start != NULL)
					{
						refs_length = i;
					}
				}
				if(i <= refs_length)
				{
					/* save a copy of the references from the original article */
					memcpy(refs_start,&t->text_base[argument2],i);
					art_out->refs_length = i;
				}
				break;

			case 9:   /* Message-ID */
				p = &t->text_base[argument2];
				quoting = 0;
				for(i=0; i<(sizeof(art_out->message_id)-1); i++)
				{
					c = p[i];
					if(c == '"') quoting ^= 1;

					if((quoting==0) && (c <= ' '))
						break;
					art_out->message_id[i] = c;
				}
				art_out->message_id[i] = 0;
				break;

			case 11:  /* Followup-To */
				followup = argument2;
				break;

			case 12:  /* reply-to */
				art_out->reply_to_in = argument2;
				art_out->reply_to_in_length = arg_length;
				break;

			case 14:   /* Cc */
				art_out->cc_start = argument2;
				art_out->cc_length = arg_length;
				break;

			case 29:   /* In-reply-to */
				quoting = 0;
				p = &t->text_base[argument2];
				for(i=0; i<(sizeof(art_out->in_reply_to)-1);)
				{
					c = *p++;
					if(c == '<')
						quoting = 1;

					if(quoting)
					{
						if(c <= ' ')
						{
							/* no closing '>'  discard message id */
							art_out->in_reply_to[0] = 0;
							break;
						}
						art_out->in_reply_to[i++] = c;
						if(c == '>') break;
					}
				}
				art_out->in_reply_to[i] = 0;
				break;

			case 32:   /* List-Post reply to mailing list */
				/*
				            art_out->list_post_start = argument2;
				            art_out->list_post_length = arg_length;
				*/
				break;
			}
		}
	}

	art_out->newsgroups = newsgroups;

	if(followup != -1)
		return(followup);
	else if(newsgroups != -1)
		return(newsgroups);
	else
		return(-t->cardex->source);
}   /* end of reply_find_newsgroups */




static int bounce_article1(CARD *cptr, int user_number, int type,int log)
/***********************************************************************/
{
	int  i;
	TEXTR textr;

	memset(&textr,0,sizeof(textr));
	textr.fr = &list_fr[0];

	if(cptr->n_cats & STATUS_BIT_ATTACH)
		type |= 0x8;
	i = bounce_article2(&textr, cptr, user_number,type,log);

	if(textr.text_base != NULL)
		flex_free((flex_ptr)&textr.text_base);
	return(i);
}   /* end of bounce_article1 */





static void dbox_reply_handler2(dbox d, void *handle,int action)
/**************************************************************/
{
	TEXTR *t = NULL;
	TEXTR *t_in;
	ARTICLE_OUT *art_out=NULL;
	int size;
	int  c;
	char *quote_str = "> ";
	int  quote_len;
	char *p;
	char *p_in;
	char *p_end;
	char *p2;
	int  i;
	int  line_length;
	int  sig_end;
	int  ng_dest;
	int  offset;
	char *subject_buf;
	char *title;
	CARD *cptr;
	CARD_EXPANDED *cardex;
	ADDR_BOOK *a;
	int  user_number;
	int  charset;

	int  remove_sig;
	int  remove_internet_header;
	int  include_attachments;
	int  attachments_size;
	int  selection;
	int  quoting;
	int  start, end;
	int  userno_reply;
	int  maillist_originator = 0;  /* reply to original sender */
	int  reply_add_text_flag = 0;
	char *author=NULL;
	char *date_str;
	char *from_to;
	int  follow_up_poster = 0;
	int  maillist_server = 0;
	int  destination_set = 0;
	int  text_quoted = 0;
	int  news_mail =0;
	int  no_request_ack = 0;
	char *str_re = "Re: ";
	char *attrib_type;
	char *attrib_str;
	int  count;
	int  cc_length;
	char *attrib[4];
	char attrib_str2[80];
	char buf[400];
	char buf2[128];
	char buf_name[128];

	if(check_lock_lists(0xffff) != 0)
		return;

	t_in = (TEXTR *)handle;
	cptr = t_in->cptr;
	cardex = t_in->cardex;

	remove_sig = dbox_getnumeric(dbox_reply,7) ^ 1;
	selection = dbox_getnumeric(dbox_reply,8);
	remove_internet_header = dbox_getnumeric(dbox_reply,10) ^ 1;
	include_attachments = dbox_getnumeric(dbox_reply,11);

	quoting = 1;
	if(dbox_getnumeric(dbox_reply,5))
		quoting = 4;
	if(dbox_getnumeric(dbox_reply,6))
		quoting = 3;
	if(dbox_getnumeric(dbox_reply,12))
		quoting = 2;


	reply_add_text_flag = 0;
	switch(action)
	{
	case 1:   /* MAIL */
		news_mail = X_MAIL;

		if(cptr->n_cats & STATUS_BIT_MAILLIST)
			maillist_originator = 1;
		break;

	case 2:   /* NEWS */
		if((cptr->n_cats & STATUS_BIT_MAILLIST) || (cptr->status & STATUS_BIT_NEWS))
		{
			news_mail = X_NEWS;
			no_request_ack = 1;
		}
		else
			news_mail = X_MAIL;
		break;

	case 3:   /* edit original */
		text_allow_edit(t_in);

		text_autosave(0,t_in);

		if((remove_sig) && (t_in->sig_start < t_in->text_length))
		{
			redraw_text_lines(t_in,0,-1);   /* do this before we remove the sig */

			sig_end = t_in->text_length;
			if((t_in->attachments) && (t_in->sig_start < t_in->text_body_end))
			{
				/* sig is before the attachments */
				sig_end = t_in->text_body_end;
			}
			move_up(t_in,sig_end,sig_end-t_in->sig_start);

			t_in->sig_start = 0x7fffffff;
			calc_line_tab(t_in);
			mark_changed(t_in);
		}
		dbox_hide(dbox_reply);
		return;

	case 9:   /* add to write news/mail window */
		t = reply_data_find(0x11);
		if(t==NULL)
		{
			dbox_hide(dbox_reply);
			return;
		}

		if(t->attachments)
		{
			werr(0,"Can't add text when the Write News/Mail has attachments");
			dbox_hide(dbox_reply);
			return;
		}
		reply_add_text_flag = 1;
		break;

	default:
		dbox_hide(dbox_reply);
		return;
	}

	dbox_hide(dbox_reply);



	if(selection && (t_in->region_start < t_in->region_end))
	{
		start = t_in->region_start;
		end = t_in->region_end;
	}
	else
	{
		if(remove_internet_header)
			start = t_in->internet_header;
		else
			start = 0;
		end = t_in->text_length;

		if(remove_sig && (t_in->sig_start < end))
			end = t_in->sig_start;

		if((t_in->attachments > 0) && (t_in->attach[0].displ < end))
			end = t_in->attach[0].displ;

		/* omit a PGP status report at the start of the text */
		if(memcmp(&t_in->text_base[start],"-----BEGIN PGP STATUS-----\n",27)==0)
		{
			start += 26;
			while((start < (end-27)) &&
					(memcmp(&t_in->text_base[start],"\n-----END PGP STATUS-----\n\n",27)!=0))
			{
				start++;
			}
			start+=27;
		}

	}

	attachments_size = 0;
	if(t_in->attachments > 0)
	{
		i = t_in->attachments - 1;
		attachments_size = t_in->attach[i].displ + t_in->attach[i].length - t_in->attach[0].displ;
	}


	if(start > end)
		start = end;


	quote_len = 0;
	switch(quoting)
	{
	case 3:   /* blank reply */
		text_quoted = 1;
		start = end = 0;
		break;

	case 2:   /* resend, no quote marks */
		str_re = "";
		break;

	case 4:   /* forward, with fordwarding indication */
		str_re = "Fwd: ";
		break;

	case 1:   /* quote text */
		if(reply_add_text_flag == 0)
			text_quoted = 1;

		quote_len = strlen(quote_str);
		break;
	}

	if(reply_add_text_flag)
	{
		include_attachments = 0;
	}

	size = (end - start) + (quote_len * t_in->n_lines) + TEXT_EXTRA;
	if(include_attachments)
		size += attachments_size;


	art_out = calloc(1,sizeof(ARTICLE_OUT));
	if(art_out == NULL)
	{
		malloc_err(23);
		return;
	}

	ng_dest = reply_find_newsgroups(t_in,art_out);
	art_out->news_mail = news_mail;
	art_out->no_request_ack = no_request_ack;

	if(reply_add_text_flag == 0)
	{

		art_out->default_user = source_to_user(cptr->source);
		art_out->quoted = text_quoted;
		art_out->supersede = reply_supersede;

		/* get user_id from original article */
		userno_reply = check_user_number(t_in->cptr->user);

		if(userno_reply == 0)
		{
			/* get default user from newsgroup */
			userno_reply = check_user_number(art_out->default_user);
		}

		/* but use the User (if one is specified) for the box in which the article was found */
		i = check_user_number(box_table[t_in->cptr->date_box >> 26].default_user);
		if(i > 0)
			userno_reply = i;


		if(t_in->internet_header==0)
		{
			werr(0,"Internet headers have not been kept for this article.  Cross-posting, references, and reply-to have been lost");

			if(art_out->news_mail == X_NEWS)
			{
				werr(0,"'Strip internet headers' option means that References have not been kept.  This message will appear out of place in some newsreaders");
			}
			str_re = "";
		}

		if(quoting == 3)
		{
			/* reply-blank */
			art_out->in_reply_to[0] = 0;
			art_out->refs_length = 0;
		}

		if(ng_dest <= 0)
		{
			strncpy(art_out->newsgs,expand_source(-ng_dest,0),sizeof(art_out->newsgs));
		}
		else
			strncpy(art_out->newsgs,&t_in->text_base[ng_dest],sizeof(art_out->newsgs));
		art_out->newsgs[sizeof(art_out->newsgs)-1] = 0;


		if(art_out->news_mail == X_NEWS)
		{
			/* get newsgroup list and message-id */

			if(quoting == 4)
			{
				if(query("Forward to a newsgroup or mailing list?",NULL)==0)
					return;
			}

			if(memcmp_lc(art_out->newsgs,"poster",6)==0)
			{
				if(cptr->n_cats & STATUS_BIT_MAILLIST)
				{
					strncpy(art_out->dest,expand_source(cptr->source,0),sizeof(art_out->dest));
					p = "List";
				}
				else
					p = "News";

				if (query2("This article requests an Email response (Followup-To is set to 'poster')","Email",p)!=0)
				{
					art_out->news_mail = X_MAIL;
					follow_up_poster = 1;
				}
				else
				{
					if((cptr->n_cats & STATUS_BIT_MAILLIST) == 0)
					{
						strncpy(art_out->newsgs,&t_in->text_base[art_out->newsgroups],sizeof(art_out->newsgs));
						art_out->newsgs[sizeof(art_out->newsgs)-1] = 0;
					}
				}
			}


			if(memcmp(art_out->newsgs,"mail.",5) == 0)
			{
				art_out->news_mail = X_MAIL;
				art_out->mailing_list = 1;

				user_number = check_user_number(t_in->cptr->user);
				if((user_number > 0) &&
						((maillist_server = options.mailbox[user_number-1].mail_list_server) != 0))
				{
					/*               strcpy(art_out->reply_to,options.mailbox[user_number-1].email_addr); */

					if((maillist_server == 1) && (dbox_persist()==0))
					{
						/* sending from a mail list group for which we are running a MANUAL mail list server.
						   Bounce the message to the mail list */

						/* save any changes first */
						if(t_in->changed)
							text_save_article(t_in);  /* !!!! This will destroy the original quoted-printable */

						/* mail list name gives a distribution list */

						if(reply_destinations(get_user_id2(user_number),&options.mailbox[user_number-1],0x10)==0)
						{
							bounce_article1(t_in->cptr,user_number-1,4,0);
						}
						else
						{
							werr(0,"Distribution list not found for Mail List '%s'",get_user_id2(user_number));
						}
						remove(fname_temp2);

						reply_set_status(t_in->fr,t_in->cptr);

						free(art_out);
						return;
					}
				}
				else if(follow_up_poster)
				{
					maillist_originator = 2;  /* reply to original poster, don't ask for confirmation */
				}
				else if((cptr->n_cats & STATUS_BIT_MAILLIST) == 0)
				{
					free(art_out);
					return;   /* disable this */

					/* send news reply to an email */
					art_out->news_mail = X_NEWS;
					art_out->dest[0]=0;
				}
				else
				{
					/* Reply to mail list */
					/* use the to: field */
					if((art_out->to_start > 0) || (art_out->list_post_start > 0))
					{
						destination_set = 1;
					}
				}
			}

		}


		if((t = text_data_init(size,art_out->news_mail)) == NULL)
		{
			free(art_out);
			return;
		}
		t->art_out = art_out;
		t->charset = t_in->charset;
		if(t->charset <= 1)
		{
			if(cardex->charset_author > 1)
				t->charset = cardex->charset_author;
			if(cardex->charset_title > 1)
				t->charset = cardex->charset_title;
		}

		if(quoting == 4)
		{
			/* forward message. don't wordwrap */
			t->wordwrap = 255;
		}

//      if((userno_reply > 0) && (&options.mailbox[userno_reply-1] != current_user))
		if(userno_reply > 0)
			user_select(t,userno_reply-1,1);
		set_sig_from_newsgroup(t,art_out->newsgs);


		for(i=10; i<=12; i++)
		{
			dbox_setfield(t->dbox_card,i,"");
		}


		if(destination_set == 0)
		{
			if(((quoting != 2) && (quoting != 4)) ||
					(cptr->status & STATUS_BIT_OG) ||
					((cptr->status & STATUS_MASK2) == STATUS_DRAFT))
			{
				strcpy(art_out->dest,cardex->author);
			}
			else
			{
				art_out->dest[0]=0;
				art_out->cc[0]=0;
			}
		}
		else
		{
			/* reply to maillist, get destination from To: address in original message */
			if(art_out->list_post_start > 0)
			{
				copy_unfold(art_out->dest,sizeof(art_out->dest),
							&t_in->text_base[art_out->list_post_start],art_out->list_post_length);
			}
			else
			{
				copy_unfold(art_out->dest,sizeof(art_out->dest),
							&t_in->text_base[art_out->to_start],art_out->to_length);
			}
		}

		if(maillist_server)
		{
			/* Operator of the maillist sending "News" reply to the maillist */
			strcpy(art_out->dest,options.mailbox[user_number-1].email_addr);
		}
		else if((art_out->reply_to_in != -1) && (art_out->reply_to_in_length > 1)
				&& ((cardex->status_other & STATUS_BIT_OG) == 0)
				&& (quoting != 2) && (quoting != 4))
		{
			/* use the reply-to field */
			if(destination_set == 0)
			{
				if(maillist_originator == 0)
				{
					copy_unfold(art_out->dest,sizeof(art_out->dest),
								&t_in->text_base[art_out->reply_to_in],art_out->reply_to_in_length);
				}
				else
				{
					/* use the Reply-To: address if it's not the same as the To: address */
					copy_unfold(buf,sizeof(buf),
								&t_in->text_base[art_out->to_start],art_out->to_length);

					copy_unfold(buf2,sizeof(buf2),
								&t_in->text_base[art_out->reply_to_in],art_out->reply_to_in_length);
					p = reply_extract_email_addr(buf2,1);

					p2 = buf;
					while((p2 = reply_extract_email_addr(p2,0)) != NULL)
					{
						if(strcmp_lc(p2,p) == 0)
						{
							/* reply-to address found in the To: line */
							break;
						}

						p2 += (strlen(p2)+1);
					}
					/* use the reply-to address if no match in the To: line, and
					   if it's not the address given in the Mailing List list */
					if((p2==NULL) && (strcmp_lc(p,&art_out->newsgs[5])!=0))
					{
						strcpy(art_out->dest,p);
					}

#ifdef deleted
					if(strcmp(reply_extract_email_addr(buf,1),p)!=0)
					{
						/* check whether the reply-to address is included in the To: address */
						if((strlen(p) > 3) && (strstr(buf,p)==0))
							strcpy(art_out->dest,p);
					}
#endif
				}
			}
		}

		/* if there is a Cc in the header, or extra addresses in the To:, copy them into the reply */
		if(art_out->news_mail == X_MAIL)
		{
			if((cardex->status_other & STATUS_BIT_OG) ||
					(cardex->status2 == STATUS_DRAFT) ||
					((quoting != 2) && (quoting != 4)))
			{
				/* don't include any CC's if we're replying directly to the originator or a mailing
				   list posting */
				if(maillist_originator == 0)
				{

					reply_copy_cc(t,t_in,cptr->status & STATUS_BIT_OG,art_out->dest);
					cc_length = strlen(art_out->cc);

					dbox_setfield(t->dbox_card,10,art_out->cc);
					art_out->orig_cc_length = cc_length;
					art_out->orig_cc_hash = get_hash9(art_out->cc);

					if(cc_length > 0)
					{
						t->button_bar_height = MAIL_BUTTON_BAR_HEIGHT2;  /* show extra fields */

						if(cc_length > (255-80))
						{
							/* too long for the CC field, use the temporary distribution list */
							dbox_setfield(t->dbox_card,10,cc_list_name(t,"CC"));
						}
					}
				}
			}
		}



		if(cptr != NULL)
		{
			if(art_out->news_mail == X_MAIL)
			{
				if((quoting != 4) && (quoting != 2))
				{
					if((cptr->status & STATUS_BIT_NEWS) && (follow_up_poster == 0))
					{
						if(!query("Send Mail reply to a News article?","OK"))
						{
							text_data_free(t);
							return;
						}
					}
					else if(maillist_originator==1)
					{
						if(!query("Send personal reply to a Mail List article?","OK"))
						{
							text_data_free(t);
							return;
						}
					}
				}
			}
			else
			{
				if((cptr->status & STATUS_BIT_NEWS) == 0)
				{
					if(!query("Send News reply to a Mail item?","OK"))
					{
						text_data_free(t);
						return;
					}
				}
			}
		}

		if((t_in->cptr->status & STATUS_MASK2) == STATUS_DRAFT)
		{
			/* retrieving a saved write news/mail article
			   Find the original article that's being replied to */
			t->cptr_save = t_in->cptr;

			visdelay2_begin();
			t->cptr = msgid_lookup(t_in->cptr->parent,t_in->cptr,0);
			visdelay2_end();

			if(t->cptr_save->status & STATUS_BIT_HDR_ONLY)
				t->changed = 1;   /* so we don't delete the article without confirmation */
		}
		else
		{
			t->cptr = t_in->cptr;
		}
		t->fr = t_in->fr;

		t->text_type = art_out->news_mail;

		if(art_out->subject_length > 0)
		{
			count = strlen(str_re);

			subject_buf = malloc(art_out->subject_length + 1);
			if(subject_buf==NULL)
			{
				malloc_err(27);
			}
			else
			{
				copy_unfold(subject_buf,art_out->subject_length+1,&t_in->text_base[art_out->subject_start],art_out->subject_length);
				charset = decode_iso8859(subject_buf,0);
				if(charset > 1)
					t->charset = charset;

				title = subject_buf;
				if(count > 0)
				{
					/* we're going to add a Re:, so strip off any previous Re:'s */
					strcpy(art_out->subject,str_re);

					while(memcmp_lc(title,"re:",3)==0)
					{
						title += 3;

						while(*title == ' ')
							title++;
					}
				}

				if(strlen(title) >= sizeof(cardex->title))
				{
					/* original subject was truncated in Pluto's index - so
					   use the original from the message text */
					strncpy0(&art_out->subject[count],title,sizeof(art_out->subject)-count);
				}
				else
				{
					sprintf(art_out->subject,"%s%s",str_re,cardex->title);
				}
				free(subject_buf);
			}
		}
		else
		{
			sprintf(art_out->subject,"%s%s",str_re,cardex->title);
		}

		reply_set_card_fields(t);
	}

	/* copy the text */

	if(art_out->supersede == 1)
	{
		sprintf(&t->text_base[t->text_length],"cancel %s\n",art_out->message_id);
		t->text_length += strlen(&t->text_base[t->text_length]);
	}

	date_str = decode_date(cptr->date_box & DATE_MASK,8);

	author = cardex->author;
	if(strchr(author,'@')==NULL)
	{
		if(art_out->from_length > 0)
		{
			interpret_sender(&t_in->text_base,art_out->from,art_out->from_length,buf2,sizeof(buf2),NULL);
			charset = decode_iso8859(buf2,1);
			if(charset > 1)
				t->charset = charset;
			author = buf2;
		}
		else
		{
			/* lookup name in address book */
			p = addr_lookup(author);
			if(p != NULL)
			{
				sprintf(buf2,"%s <%s>",author,p);
				author = buf2;
			}
		}
	}

	if((end > start) & (quoting == 1))
	{
		buf[0]=0;

		if(cardex->status_other & STATUS_BIT_OG)
		{
			attrib_type="Y1";
			i = cptr->user & 0x1f;
			if(i > 0)
				author = options.mailbox[i-1].email_addr;
			else
				author = "I";
		}
		else
		{

			if(((art_out->news_mail == X_NEWS) || (cptr->n_cats & STATUS_BIT_MAILLIST))
					/*  && (reply_add_text_flag == 0) */  && (art_out->message_id[0] != NULL))
				attrib_type = "Y2";
			else if((cptr != NULL) && (cptr->status & STATUS_BIT_NEWS))
				attrib_type = "Y3";
			else
				attrib_type = "Y4";

		}

		attrib_str = msgs_lookup(attrib_type);
		if(attrib_str != NULL)
		{
			for(i=0; i<4; i++)
				attrib[i] = "";

			count =0;
			for(i=0; (i < (sizeof(attrib_str2)-1)) && ((c = attrib_str[i]) != 0); i++)
			{
				if(c == '|')
					c = '\n';

				attrib_str2[i] = c;

				if(c == '%')
				{
					p = NULL;
					switch(attrib_str[i+1])
					{
					case 'A':    /* author including email address */
						p = author;
						break;
					case 'B':    /* author, name only */
						p = author;
						while(isspace(*p)) p++;
						strcpy(buf_name,p);
						p = buf_name;

						if(buf_name[0] == '<')
						{
							/* no name, only an address */
							if((p2 = strchr(buf_name,'@')) != NULL)
							{
								p2[0] = 0;   /* take name part only of address */
								p = &buf_name[1];
							}
						}
						else if((p2 = strchr(buf_name,'<')) != NULL)
						{
							if(p2[-1]==' ')
								p2--;
							*p2 = 0;
						}
						break;
					case 'D':
						p = date_str;
						break;
					case 'M':
						p = art_out->message_id;
						break;
					case 'N':
						p = expand_source(cptr->source,0);
						break;
					}
					if(p != NULL)
					{
						attrib[count++] = p;
						i++;
						attrib_str2[i] = 's';
					}
				}
			}
			attrib_str2[i]=0;
			sprintf(buf,attrib_str2,attrib[0],attrib[1],attrib[2],attrib[3]);
		}

		strcpy(&t->text_base[t->text_length],buf);
		t->text_length += strlen(buf);
	}

	if((end > start) & (quoting == 4))
	{
		/* Forward */
		date_str = decode_date(cptr->date_box & DATE_MASK,3);
		buf2[0]=0;
		if(cptr->status & STATUS_BIT_NEWS)
			sprintf(buf2,"Newsgroup: %s\n",expand_source(cptr->source,0));
		else if(cptr->n_cats & STATUS_BIT_MAILLIST)
			sprintf(buf2,"Mailing-List: %s\n",expand_source(cptr->source,3));

		if(cptr->status & STATUS_BIT_OG)
			from_to = "To:  ";
		else
			from_to = "From:";

		sprintf(buf,"\n------ Forwarded message  ------\n%s %s\nDate: %s\nSubject: %s\n%s\n",from_to,author,date_str,cardex->title,buf2);

		strcpy(&t->text_base[t->text_length],buf);
		t->text_length += strlen(buf);
		size += 40;  /* to allow for 'end forwarded message' text */
	}

	size += t->text_length;
	if(size > t->text_buf_size)
	{
		/* this is needed in case we are adding to an existing write window */
		if(flex_extend((flex_ptr)&t->text_base,size) == 1)
			t->text_buf_size = size;
		else
			malloc_err(22);
	}

	p = &t->text_base[t->text_length];
	p_in = &t_in->text_base[start];
	p_end = &t_in->text_base[end];

	c = '\n';
	line_length = 0;
	while(p_in < p_end)
	{
		if((c == '\n') && (*p_in != '\n') && (p_in < p_end))
		{
			/* insert quote string */
#ifdef deleted
			/* use "> ", but ">" before text that's already quoted */
			*p++ = '>';
			line_length++;

			if(*p_in != '>')
			{
				*p++ = ' ';
				line_length++;
			}
#else
			/* use "> " always */
			line_length = quote_len;
			for(i=0; i<quote_len; i++)
			{
				*p++ = quote_str[i];
			}
#endif

		}
		c = (*p++ = *p_in++);
		line_length++;

		if(c == '\n')
			line_length = 0;

	}
	*p++ = '\n';

	if(quoting==4)
	{
		sprintf(buf,"------ End forwarded message ------\n");
		strcpy(p,buf);
		p += strlen(buf);
	}
	t->text_body_end = t->text_length = p - t->text_base;

	if(include_attachments)
	{
		attachments_extend(t,t_in->attachments+1);

		memcpy(p,&t_in->text_base[t_in->attach[0].displ],attachments_size);
		memcpy(t->attach,t_in->attach,sizeof(t->attach[0])*t_in->attachments);

		offset = t->text_body_end - t_in->text_body_end;

		for(i=0; i<t_in->attachments; i++)
		{
			t->attach[i].displ += offset;
		}

		t->attachments = t_in->attachments;

		t->text_length = t->text_body_end + attachments_size;

		t->boundary_string_len = t_in->boundary_string_len;
		strcpy(t->boundary_string,t_in->boundary_string);

		show_attachment_icons(t);
	}

	t->ole = 0;
	if(options.ext_edit)
	{
		reply_start_OLE(t);  /* use external editor */
	}
	else
	{
		fade_ext_edit(t->w_card,0);   /* un-fade Post button */
	}

	calc_line_tab(t);
	redraw_text_lines(t,0,-1);

	/* lookup destination address in the address book to see whether
	   there's a specified User and Sig */
	if(t->text_type == X_MAIL)
	{
		if((a = addr_lookup_url(reply_extract_email_addr(art_out->dest,2)))!=NULL)
		{
			reply_addrbook_sig(t,a);
		}
	}

	open_article(t,5);
	set_caret_pos(t);
	text_autosave(0,t);

	if(reply_add_text_flag)
	{
		free(art_out);
	}
}   /* end of dbox_reply_handler2 */




static void dbox_reply_handler(dbox d, void *handle)
/**************************************************/
{
	int action;

	action = dbox_get(d);
	dbox_reply_handler2(d,handle,action);
}   /* end of dbox_reply_handler */




BOOL dbox_reply_raw_handler(dbox d, void *event, void *handle)
/************************************************************/
{
	wimp_eventstr *e;
	wimp_mousestr *mouse;
	TEXTR *t_in;

	t_in = (TEXTR *)handle;

	e = (wimp_eventstr *)event;

	switch (e->e)
	{
	case wimp_EBUT:
		/* click on icon.  get icon number. */
		mouse = &e->data.but.m;
		switch(mouse->i)
		{
		case 5:
		case 12:
			/* set attachments option if there are any attachments, but not
			   multipart-alternative */
			if((t_in->attachments) && (t_in->multi_alternative == 0))
				dbox_setnumeric(d,11,1);
			break;

		case 4:
		case 6:
			if(dbox_getnumeric(d,11))
				dbox_setnumeric(d,11,0);
			break;

		}
		break;
	}
	return(help_handler(event,HELP_REPLY));
}   /* end of dbox_reply_raw_handler */



int text_check_explicit_selection(TEXTR *t)
/*****************************************/
{
	int  i;
	int  len;
	int  selection = 0;

	if((i = t->region_end - t->region_start) > 0)
	{
		/* there is selected text.  Set "selection" option unless this is as a
		   result of a search */
		len = strlen(search_text_string);

		if((len != i) || (memcmp_lc(&t->text_base[t->region_start],search_text_string,len) != 0))
		{
			len = strlen(search_text_string_open);
			if((len != i) || (memcmp_lc(&t->text_base[t->region_start],search_text_string_open,len) != 0))
				selection = 1;
		}
	}
	return(selection);
}   /* end of text_check_explicit_selection */



void edit_reply(TEXTR *t_in, int action)
/**************************************/
/* Action:
   bits 0-2  auto-press button,  1=mail, 2=news
   bits 4-5  set option 0=quote, 1=forward, 2=blank, 3=resend
   bit  8    supersede
   bit  12   include attachments
   bit  13   include signature
*/
{
	int  i;
	char *name1;
	char *name2;
	int  status1;
	int  status3;

	static char buttons[] = {4,5,6,12};

	reply_supersede = (action >> 8) & 0xf;

	dbox_eventhandler(dbox_reply,dbox_reply_handler,(void *)t_in);
	dbox_raw_eventhandler(dbox_reply,dbox_reply_raw_handler,(void *)t_in);


	dbox_setnumeric(dbox_reply,8,text_check_explicit_selection(t_in));

	dbox_setnumeric(dbox_reply,7,action & 0x2000);   /* include sig */
	dbox_setnumeric(dbox_reply,10,0);  /* include internet header */

	if(t_in->attachments == 0)
		action &= ~0x1000;

	dbox_setnumeric(dbox_reply,11,action & 0x1000);  /* include attachments */

	for(i=4; i<=6; i++)
		dbox_setnumeric(dbox_reply,i,0);
	dbox_setnumeric(dbox_reply,12,0);

	i = buttons[(action >> 4) & 7];
	dbox_setnumeric(dbox_reply,i,1);

	if(action & 7)
	{
		dbox_reply_handler2(dbox_reply,(void *)t_in,action & 7);
	}
	else
	{
		dbox_unfadefield(dbox_reply,2);
		name1 = "Mail sender";

		status1 = t_in->cptr->status;
		status3 = t_in->cptr->n_cats;
		if(status3 & STATUS_BIT_MAILLIST)
			name2 = "Mail list";
		else if(status1 & STATUS_BIT_NEWS)
			name2 = "News";
		else
		{
			name1 = "Mail";
			name2 = "";
			dbox_fadefield(dbox_reply,2);
		}

		dbox_setfield(dbox_reply,1,name1);
		dbox_setfield(dbox_reply,2,name2);

		dbox_hide(dbox_reply);

		dbox_showstatic(dbox_reply);
		dbox_text_corner(t_in,dbox_reply);
	}
}  /* end of edit_reply */







TEXTR *new_reply(FOLDREC *fr, char *email_addr, char *newsgroups, FOLDREC *parent, int usernum, char *sig)
/******************************************************************************************************/
/* Create a blank reply window */
{
	CARD *cptr = NULL;
	TEXTR *t;
	ARTICLE_OUT *art_out;
	ADDR_BOOK *a;
	int  i;
	char *param;
	char *source_name;
	int  news_mail;
	CARD_EXPANDED card_expanded;
	char body[200];

	t = reply_data_find(0);  /* not used */

	art_out = calloc(1,sizeof(ARTICLE_OUT));
	if(art_out == NULL)
	{
		malloc_err(24);
		return(NULL);
	}

	/* news or mail, and which newsgroup? */
	body[0] = 0;
	news_mail = X_MAIL;

	if(email_addr != NULL)
	{
		if(memcmp_lc(email_addr,"mailto:",7)==0)
			email_addr += 7;   /* delete the mailto: */

		if((param = strchr(email_addr,'?')) != NULL)
		{
			get_url_parameters(art_out,email_addr,param,body);
		}
		else
		{
			copy_url_param(art_out->dest,email_addr,strlen(email_addr));
#ifdef deleted
			if(strchr(email_addr,',')!=NULL)
				sprintf(art_out->dest,"\"%s\"",email_addr);
			else
				strcpy(art_out->dest,email_addr);
#endif
		}
		news_mail = X_MAIL;


	}
	else if(newsgroups != NULL)
	{
		news_mail = X_NEWS;
		source_name = newsgroups;
	}
	if((fr != NULL) && (fr->n_entries > 0)
			&& (fr->ixlist[fr->cursor_ref] & IXLIST_SELECTED))
	{

		cptr = cardfile_cptr(fr,fr->cursor_ref);
		unpack_card(cptr,&card_expanded);

		if((fr->display_levels - fr->cursor_level) < 2)
			strcpy(art_out->subject,card_expanded.title);

		source_name = expand_source(cptr->source,0);

		if(cptr->status & STATUS_BIT_NEWS)
		{
			news_mail = X_NEWS;
		}
		else if(cptr->n_cats & STATUS_BIT_MAILLIST)
		{
			if(memcmp(source_name,"mail.",5)==0)
				strcpy(art_out->dest,&source_name[5]);
			else
				strcpy(art_out->dest,card_expanded.author);
		}
		else
		{
			strcpy(art_out->dest,card_expanded.author);
		}
	}


	if((t = text_data_init(TEXT_EXTRA,news_mail)) == NULL)
	{
		free(art_out);
		return(NULL);
	}
	t->art_out = art_out;
	t->parent = parent;
	t->cptr = NULL;

	if(body[0] != 0)
	{
		strcpy(t->text_base,body);
		t->text_length = strlen(body);
	}
	if(usernum > 0)
	{
		t->selected_user = &options.mailbox[usernum-1];
		t->selected_user_num = usernum-1;
		strcpy(t->selected_sig,make_legal_fname(t->selected_user->signature));
	}
	if((sig != NULL) && (sig[0] > ' '))
	{
		strcpy(t->selected_sig,sig);
	}

	if(news_mail == X_NEWS)
	{
		t->button_bar_height = NEWS_BUTTON_BAR_HEIGHT;

		/* get newsgroup list and message-id */
		strncpy(art_out->newsgs,source_name,sizeof(art_out->newsgs));
		if(memcmp(art_out->newsgs,"mail.",5)==0)
			art_out->newsgs[0] = 0;

		set_sig_from_newsgroup(t,source_name);
	}
	else
	{
		t->button_bar_height = MAIL_BUTTON_BAR_HEIGHT;

		dbox_setnumeric(t->dbox_card,7,current_user->request_acks);
		dbox_setfield(t->dbox_card,12,"");
	}

	if((cptr != NULL) && (cptr->n_cats & STATUS_BIT_MAILLIST))
	{
		if(news_mail != X_NEWS)
			dbox_setnumeric(t->dbox_card,7,0);   /* no request_acks for mailing list */
		set_sig_from_newsgroup(t,source_name);
	}

	reply_set_ext_edit(t,0);


	reply_show_user_id(t);
	for(i=8; i<=11; i++)
	{
		dbox_setfield(t->dbox_card,i,"");
	}

	if(news_mail == X_NEWS)
		dbox_setfield(t->dbox_card,9,art_out->newsgs);
	else
	{
		dbox_setfield(t->dbox_card,9,art_out->dest);
		dbox_setfield(t->dbox_card,10,art_out->cc);

		/* lookup address book to see if there's a User or Sig set
		   for this address */
		if((a = addr_lookup_url(reply_extract_email_addr(art_out->dest,3)))!=NULL)
		{
			reply_addrbook_sig(t,a);
		}

	}
	dbox_setfield(t->dbox_card,8,art_out->subject);
	dbox_setfield(t->dbox_card,4,mime_style_names[t->use_mime]);

	art_out->news_mail = news_mail;

	t->text_length = 0;
	if(body[0] != 0)
	{
		strcpy(t->text_base,body);
		t->text_length = strlen(body);
	}
	t->text_base[t->text_length++] = '\n';
	t->text_body_end = t->text_length;
	t->attachments = 0;
	t->text_type = news_mail;

	fade_ext_edit(t->w_card,0);   /* unfade post and editor buttons */
	calc_line_tab(t);
	redraw_text_lines(t,0,-1);
	open_article(t,5);
	set_caret_pos(t);
	text_autosave(0,t);
	return(t);
}   /* end of new_reply */




void reply_M_URL(wimp_eventdata *d, int protocol)
/***********************************************/
/* A URL broadcast, is it a mailto:
   Protocol: 0=Acorn, 1=ANT */
{
	char *url;
	int  flags=0;
	wimp_msgstr *m;
	int  size;
	int  handle;


	m = &d->msg;

	if(protocol==0)
	{
		url = (char *)m->data.words[1];
		flags = m->data.words[0];
	}
	else
	{
		url = m->data.chars;

		/* check for indirected form of the ANT lauch protocol */
		if(m->data.words[0] == NULL)
			url = (char *)m->data.words[1];
	}

	if(memcmp_lc(url,"mailto:",7) ==0)
	{
		/* send an acknowledgement */
		m->hdr.your_ref = m->hdr.my_ref;
		wimp_sendmessage(wimp_EACK,m,0);

		if(protocol == 0)
		{
			/* Acorn URI protocol, we need to fund the size of a buffer for
			   the URI and allocate it */
			handle = m->data.words[2];
			os_swi4r(0x4e382,0,0,0,handle,NULL,NULL,&size,NULL);
			url = malloc(size);
			if(url == NULL)
				return;
			os_swi4(0x4e382,0,(int)url,size,handle);
		}

		if((flags & 1) == 0)
		{
			new_reply(NULL,&url[7],NULL,NULL,0,NULL);
		}

		if(protocol == 0)
			free(url);
	}
}   /* end of reply_M_URL */


